/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.sdcache.distributed.client;

import java.io.IOException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 *
 * @author chaitanya
 */
public class ClientSocketInterface extends Thread
{

    protected Socket socket;
    private Receiver receiver;
    private Sender sender;
    private Processor processor;
    private  boolean running;
    private  BlockingQueue inQ;
    private  BlockingQueue outQ;
    private String host;
    private int port;
    private String ping;
    private String regTag;
    private int noOfHandlers=1;
    private ResponseHandler handlers[];
    private SocketListener sl=null;

    public ClientSocketInterface(String name,String host,int port,Processor processor)
    {
        this(name, host, port, processor, 1);
    }
    
    public ClientSocketInterface(String name,String host,int port,Processor processor, int noOfHandlers)
    {
        super(name+" Server");
        this.host=host;
        this.port=port;
        this.processor=processor;
        this.processor=processor;
        
        inQ= new LinkedBlockingQueue<String>();
        outQ= new LinkedBlockingQueue<String>();
        this.noOfHandlers=noOfHandlers;
        
        
        handlers= new ResponseHandler[noOfHandlers];
        for(int i=0;i<noOfHandlers;i++)
        {
            handlers[i]=new ResponseHandler(name, this, processor);
            handlers[i].start();
            //System.out.println("-----------------------------");
        }
    }
        
    public BlockingQueue<String> getInQ()
    {
        return inQ;
    }
    public BlockingQueue<String> getOutQ()
    {
        return outQ;
    }
            
    public void setRunning(boolean running)
    {
        this.running = running;
    }

    public boolean isRunning()
    {
        return running;
    }
    

  
    
     public  void sendObject(Object object)
    {
        try
        {
            outQ.put(object);
        } catch (InterruptedException ex)
        {
        }
    }
    
    public Object getObject()
    {
        Object object = null;
        try
        {
            object = inQ.take();
        } catch (InterruptedException ex)
        {
        }
        return object;
    }

    @Override
    public void run()
    {
        while (true)
        {
            try
            {
                connectToServer();     //Connect to Server     

                if(sl!=null)
                    sl.connected(new SocketEvent("Sockect Connected", this));
                while (running)
                {
                    Thread.sleep(5000);
                }// Checking the Connectivity
                System.out.println(getName()+" >================>  Disconnected  ");
                disconnect();
                Thread.sleep(1000);
            } catch (Exception e)
            {
            }
        }
    }

    /**
     * Connect to Server
     */
    private void connectToServer()
    {
        if (socket == null || !socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown())
        {

            do
            {
                try
                {
                    Thread.sleep(5000);
                } catch (InterruptedException ioe)
                {
                    ioe.printStackTrace();
                } catch (Exception e)
                {
                    System.out.println("Exception");
                }
                //System.out.println(getName()+" >================>  inside the getReadyToCommunicate()  ");
                connect();
            } while (socket == null);
        }
        System.out.println(getName()+" >================>  Connected  ");
    }
    
    /**
     * Connect to The Ati Server
     */
    private void connect()
    {
        try
        {
            socket = new Socket(host,port);

            receiver = new Receiver(this.getName(),socket,this);
            sender = new Sender(this.getName(),socket,this);

            running=true;
            try
            {
                receiver.start();
            } catch (IllegalThreadStateException itse)
            {
                itse.printStackTrace();
            }

            try
            {
                sender.start();
            } catch (IllegalThreadStateException itse)
            {
                itse.printStackTrace();
            }
        /*	try {		        
        System.out.println(" ******Before the sockettrdServer ***** ");
        thread.start();
        }catch(IllegalThreadStateException itse) {
        itse.printStackTrace();
        log.logMessage("SocketConnection","SocketInterface::connect() IllegalThreadStateException while starting Sender: " + itse.toString(),"Debug");
        }*/

        } catch (UnknownHostException uhe)
        {
            System.out.println("Problem connecting to "+getName()+" -> Unknown Host Exception  ");
            disconnect();
        } catch (NoRouteToHostException nrthe)
        {
            System.out.println("Problem connecting to  "+getName()+" -> No Route To Host Exception  ");
            disconnect();
        } catch (ConnectException ce)
        {
            //System.out.println("Problem connecting to  "+getName()+" -> Connect Exception");
            disconnect();
        } catch (IOException ioe)
        {
            System.out.println("Problem connecting to  "+getName()+" -> IO Exception ");
            disconnect();
        } catch (Exception e)
        {
            disconnect();
        }
    }

    public void disconnect()
    {
        if(sl!=null)
            sl.disconnected(new SocketEvent("Sockect Desconnected", this));
        try
        {
            try
            {
                receiver.join();
                sender.join();
            } catch (InterruptedException ie)
            {

            } catch (Exception e)
            {
            }

            if (socket != null)
            {
                socket.close();
            }

        } catch (IOException ioe)
        {
        //throw ioe;
        } finally
        {
            socket = null;
        }
    }
    public void log(String message,String id)
    {
    }
    

    
    public void addListener(SocketListener sl)
    {
        this.sl=sl;
    }
}
